package com.platform.comm.validation;

import com.google.common.base.Strings;
import com.platform.comm.exceptions.ValidationException;
import com.platform.comm.util.IdCardUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.regex.Pattern;

/**
 * Title: ValidationHelper
 * Description: 简单验证实现辅助类
 * Date 2020/5/15
 *
 * @author wxw
 * @version v1.0
 */
@SuppressWarnings("all")
public class ValidatorHelper {

    public static String phoneRegexp = "^((0\\d{2,3}-\\d{7,8})|(1[35874]\\d{9}))$";
    public static String idCodeRegexp = "^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[012]))(([012]\\d)|3[01])\\d{3}([\\d|X])$";
    public static String emailRegexp = "[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?";
    public static String unifiedCodeRegexp = "^[0-9ABCDEFGHJKLMNPQRTUWXY]{18}$";
    public static String regNoRegexp = "^[0-9]{15}$";
    public static String orgInstCodeRegex = "^[0-9A-Z]{8}(-)?[0-9X]$";
    public static String dateFormatRegex = "^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])" +
            "|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)" +
            "|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]" +
            "|[2468][048]|[13579][26])00)-02-29)$";


    public static boolean validateRegNo(String regNo) {
        return Pattern.compile(regNoRegexp).matcher(regNo).matches() && checkRegNo(regNo);
    }

    public static boolean validateOrgInstCode(String orgInstCode) {
        return Pattern.compile(orgInstCodeRegex).matcher(orgInstCode).matches() && checkOrgInstCode(orgInstCode);
    }

    public static boolean validateUnifiedCode(String unifiedCode) {
        return Pattern.compile(unifiedCodeRegexp).matcher(unifiedCode).matches() && checkUnifiedCode(unifiedCode) ||
                "00000000000000000X".equals(unifiedCode.toUpperCase());
    }

    public static boolean validateRegexp(String regexp, String value) {
        return Pattern.compile(regexp).matcher(value).matches();
    }

    public static boolean validatePhone(String value) {
        return Strings.isNullOrEmpty(value) ? true: validateRegexp(phoneRegexp, value);
    }

    public static boolean validateEmail(String value) {
        return Strings.isNullOrEmpty(value) ? true: validateRegexp(emailRegexp, value);
    }

    public static boolean validateDate(String value) {
        return Pattern.compile(dateFormatRegex).matcher(value).matches();
    }

    public static boolean validateIdCode(String idCode) {
        return IdCardUtil.isValidate18IdCard(idCode);
    }

    public static boolean validateIdCodeByRegexp(String value) {
        return Strings.isNullOrEmpty(value) ? true: validateRegexp(idCodeRegexp, value);
    }

    private static boolean checkUnifiedCode(String unifiedCode) {
        String code = "0123456789ABCDEFGHJKLMNPQRTUWXY";
        int sum = 0, a;
        int[] MD = {1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28};
        for (int i = 0; i < 17; i++) {
            a = code.indexOf(unifiedCode.charAt(i));
            if (a < 0) {
                return false;
            }
            sum += a * MD[i];
        }
        sum %= 31;
        char checkCode = code.charAt((31 - sum) % 31);
        return checkCode == unifiedCode.charAt(17);
    }

    private static boolean checkRegNo(String regNo) {
        int p = 10, s = 0;
        for (int i = 0; i < 15; i++) {
            s = (p % 11) + Integer.parseInt(regNo.charAt(i) + "");
            p = (s % 10) * 2;
            if (p == 0) {
                p = 20;
            }
        }
        return 1 == s % 10;
    }

    private static boolean checkOrgInstCode(String orgInstCode) {
        orgInstCode = orgInstCode.replaceAll("-", "");
        String code = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        String CC = "0123456789X0";
        int sum = 0, a;
        int[] MD = {3, 7, 9, 10, 5, 8, 4, 2};
        for (int i = 0; i < 8; i++) {
            a = code.indexOf(orgInstCode.charAt(i));
            if (a < 0) {
                return false;
            }
            sum += a * MD[i];
        }
        sum %= 11;
        char checkCode = CC.charAt(11 - sum);
        return checkCode == orgInstCode.charAt(8);
    }

    public static int $bytesCount(String value, String encode) {
        int c = 0, count = 0;
        switch (encode) {
            case "utf-8":
                for (int i = 0; i < value.length(); i++) {
                    c = value.charAt(i);
                    if ((c >= 0x0001) && (c <= 0x007F)) {
                        count++;
                    } else if (c > 0x07FF) {
                        count += 3;
                    } else {
                        count += 2;
                    }
                }
                return count;
            default: // 按GB码计算（不处理4字节字符）
                for (int i = 0; i < value.length(); i++) {
                    c = value.charAt(i);
                    if ((c >= 0x0001) && (c <= 0x00FF)) {
                        count++;
                    } else {
                        count += 2;
                    }
                }
                break;
        }
        return count;
    }

    public static void process(Predicate<String> predicate, String realValue, String message) {
        if (Objects.nonNull(realValue) && predicate.negate().test(realValue)) {
            throw new ValidationException(message);
        }
    }

    public static void process(BiPredicate<String, String> predicate, String value, String realValue, String message) {
        if (Objects.nonNull(realValue) && StringUtils.isNotEmpty(value) && predicate.negate().test(realValue, value)) {
            throw new ValidationException(message);
        }
    }

    public static void main(String[] args) {
        String email = "1@qq.com";
        System.out.println(Pattern.compile(emailRegexp).matcher(email).matches());
        String orgInstCode = "31257195-3";
        System.out.println(Pattern.compile(orgInstCodeRegex).matcher(orgInstCode).matches());
        System.out.println(checkOrgInstCode(orgInstCode.replaceAll("-", "")));

    }
}
